const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const cors = require('@koa/cors')
const static = require('koa-static')
const path = require('path')
const session = require('koa-generic-session')
const redisStore = require('koa-redis')
const { koaBody } = require('koa-body')
const auth = require('./middleware/auth')
const redis = require('./db/redis')

// 创建应用实例
const app = new Koa()

// 开启DEBUG模式，记录更多信息
const DEBUG = true

// 错误处理中间件 - 必须放在第一位
app.use(async (ctx, next) => {
  try {
    await next()
    // 如果是404，提供更详细的信息
    if (ctx.status === 404) {
      ctx.status = 404
      ctx.body = {
        code: 404,
        message: `无法找到路由: ${ctx.method} ${ctx.url}`,
        path: ctx.path
      }
      console.warn(`⚠️ 404错误: ${ctx.method} ${ctx.url}`)
    }
  } catch (err) {
    console.error(`❌ 请求处理错误: ${ctx.method} ${ctx.url}`, err)
    ctx.status = err.status || 500
    ctx.body = {
      code: err.status || 500,
      message: err.message || '服务器内部错误',
      path: ctx.path,
      error: DEBUG ? err.stack : undefined
    }
  }
})

// 请求日志中间件
app.use(async (ctx, next) => {
  const start = Date.now()
  console.log(`=> ${ctx.method} ${ctx.url} 开始处理`)
  await next()
  const ms = Date.now() - start
  console.log(`<= ${ctx.method} ${ctx.url} ${ctx.status} 处理完成 +${ms}ms`)
})

// 配置session和Redis
app.keys = ['zhuanz-secret-key']
app.use(session({
  key: 'zhuanz:sess',
  prefix: 'zhuanz:sess:',
  cookie: {
    path: '/',
    httpOnly: true,
    maxAge: 24 * 60 * 60 * 1000 // 1天
  },
  store: redisStore({
    host: '127.0.0.1',
    port: 6379
  })
}))

// CORS配置
app.use(cors({
  origin: (ctx) => {
    const validOrigins = [
      'http://localhost:8089',
      'http://127.0.0.1:8089'
    ]
    const origin = ctx.request.header.origin
    if (validOrigins.includes(origin)) {
      return origin
    }
    return false
  },
  credentials: true,
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
  exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
  maxAge: 5,
}))

// 文件上传配置
app.use(koaBody({
  multipart: true,
  formidable: {
    uploadDir: path.join(__dirname, 'public/uploads/temp'),
    keepExtensions: true,
    maxFieldsSize: 2 * 1024 * 1024,
  }
}))

// 解析请求体
app.use(bodyParser())

// 静态文件服务
app.use(static(path.join(__dirname, 'public')))

// 认证中间件
app.use(auth)

// 安全加载路由函数
function loadRouter(routePath) {
  try {
    const router = require(routePath)
    if (!router || typeof router.routes !== 'function') {
      console.error(`错误: ${routePath} 没有导出有效的路由对象`)
      return null
    }
    console.log(`✅ 成功加载路由: ${routePath}`)
    return router
  } catch (err) {
    console.error(`❌ 加载路由 ${routePath} 失败:`, err.message)
    return null
  }
}

// 注册路由函数 - 完全重写
function registerRouter(app, router, prefix = '') {
  if (!router) {
    return false
  }
  
  try {
    app.use(router.routes())
    app.use(router.allowedMethods())
    
    const actualPrefix = router.opts.prefix || prefix || '/api'
    console.log(`✅ 路由已注册，前缀: ${actualPrefix}`)
    return true
  } catch (err) {
    console.error(`❌ 注册路由失败:`, err.message)
    return false
  }
}

// 注册路由时不附加前缀，因为路由文件中已经定义了前缀
console.log('开始注册路由...')

// 1. 加载主路由 - 单独处理，因为它没有前缀
const indexRouter = loadRouter('./routes/index')
if (indexRouter) {
  app.use(indexRouter.routes())
  app.use(indexRouter.allowedMethods())
  console.log('✅ 主路由已注册')
}

// 2. 加载并注册小程序端API路由
console.log('注册小程序API路由...')
const apiRouters = [
  './routes/home',
  './routes/teachers',
  './routes/course',
  './routes/user',
  './routes/points',
  './routes/mall', 
  './routes/report',
  './routes/login',
  './routes/assistant',
  './routes/stores',
  './routes/category',
  './routes/booking'
]

// 注册小程序API路由
apiRouters.forEach(path => {
  const router = loadRouter(path)
  if (router) {
    app.use(router.routes())
    app.use(router.allowedMethods())
    console.log(`✅ 路由已注册: ${path}`)
  }
})

// 3. 加载并注册管理后台路由
console.log('注册管理后台API路由...')
const adminRouters = [
  './routes/admin/banner',
  './routes/admin/course',
  './routes/admin/appointment',
  './routes/admin/evaluation',
  './routes/admin/statistics',
  './routes/admin/profile',
  './routes/admin/orders'
]

// 注册管理后台路由
adminRouters.forEach(path => {
  const router = loadRouter(path)
  if (router) {
    app.use(router.routes())
    app.use(router.allowedMethods())
    console.log(`✅ 管理后台路由已注册: ${path}`)
  }
})

// 4. 埋点路由 - 特殊处理
try {
  // 检查weblog目录是否存在
  const fs = require('fs')
  const weblogPath = path.join(__dirname, 'routes/weblog')
  
  if (!fs.existsSync(weblogPath)) {
    throw new Error(`weblog路由目录不存在: ${weblogPath}`)
  }
  
  // 使用原始 koa-router 方式定义路由
  const Router = require('koa-router')
  
  // 创建埋点数据路由
  const trackRouter = new Router()
  
  // 数据库连接
  const db = require('./db')
  
  // 测试接口
  trackRouter.get('/api/weblog/track/test', async (ctx) => {
    ctx.body = {
      code: 200,
      message: 'weblog track接口可以访问',
      timestamp: new Date().toISOString()
    }
  })
  
  // 埋点数据接收接口
  trackRouter.post('/api/weblog/track', async (ctx) => {
    try {
      const { events, deviceInfo } = ctx.request.body
      
      if (!events || !Array.isArray(events) || events.length === 0) {
        ctx.body = {
          code: 400,
          message: '无效的埋点数据'
        }
        return
      }
      
      console.log('📊 收到埋点数据:', events.length, '条事件')
      
      // 获取设备信息字符串
      const deviceInfoStr = deviceInfo ? JSON.stringify(deviceInfo) : null
      
      // 处理每个事件
      const insertPromises = events.map(async (event) => {
        const {
          user_id,
          event_type,
          timestamp,
          course_id,
          extra_data
        } = event
        
        // 确保额外数据是字符串
        const extraDataStr = extra_data ? JSON.stringify(extra_data) : null
        
        // 尝试两种方式写入数据，支持有无device_info字段的表结构
        try {
          try {
            // 先尝试包含device_info的方式
            await db.executeQuery(
              `INSERT INTO user_behaviors 
               (user_id, event_type, timestamp, course_id, extra_data, device_info) 
               VALUES (?, ?, ?, ?, ?, ?)`,
              [user_id, event_type, timestamp, course_id || null, extraDataStr, deviceInfoStr]
            )
          } catch (error) {
            if (error.code === 'ER_BAD_FIELD_ERROR') {
              // 如果字段不存在，使用不包含device_info的插入方式
              await db.executeQuery(
                `INSERT INTO user_behaviors 
                 (user_id, event_type, timestamp, course_id, extra_data) 
                 VALUES (?, ?, ?, ?, ?)`,
                [user_id, event_type, timestamp, course_id || null, extraDataStr]
              )
            } else {
              throw error // 其他错误则继续抛出
            }
          }
          console.log(`✅ 埋点数据写入成功: ${event_type}`)
          return true
        } catch (err) {
          console.error(`❌ 埋点数据写入失败:`, err.message)
          return false
        }
      })
      
      // 等待所有写入完成
      const results = await Promise.all(insertPromises)
      const successCount = results.filter(r => r).length
      
      ctx.body = {
        code: 200,
        message: `成功记录 ${successCount}/${events.length} 条埋点数据`,
        success: successCount,
        total: events.length
      }
    } catch (err) {
      console.error('处理埋点数据失败:', err)
      ctx.body = {
        code: 500,
        message: '服务器内部错误',
        error: err.message
      }
    }
  })
  
  // 获取最近埋点数据接口
  trackRouter.get('/api/weblog/track/recent', async (ctx) => {
    try {
      const { limit = 100 } = ctx.query
      
      // 获取最近埋点数据
      const rows = await db.executeQuery(
        `SELECT * FROM user_behaviors 
         ORDER BY timestamp DESC 
         LIMIT ?`,
        [Math.min(parseInt(limit), 500)]
      )
      
      // 解析JSON字符串为对象
      const data = rows.map(row => {
        const result = { ...row }
        
        // 解析extra_data
        if (row.extra_data) {
          try {
            result.extra_data = JSON.parse(row.extra_data)
          } catch (e) {
            result.extra_data = row.extra_data
          }
        }
        
        // 解析device_info
        if (row.device_info) {
          try {
            result.device_info = JSON.parse(row.device_info)
          } catch (e) {
            result.device_info = row.device_info
          }
        }
        
        return result
      })
      
      ctx.body = {
        code: 200,
        message: '获取最近埋点数据成功',
        data
      }
    } catch (err) {
      console.error('获取埋点数据失败:', err)
      ctx.body = {
        code: 500,
        message: '服务器内部错误',
        error: err.message
      }
    }
  })
  
  // 注册路由
  app.use(trackRouter.routes())
  app.use(trackRouter.allowedMethods())
  
  console.log('✅ 埋点路由注册成功')
} catch (err) {
  console.error('❌ 注册埋点路由失败:', err.message)
}

// 启动服务器
const PORT = 3000
const server = app.listen(PORT, () => {
  console.log(`🚀 服务器已启动，运行在 http://localhost:${PORT}`)
})

// 优雅关闭服务
process.on('SIGINT', async () => {
  console.log('服务正在关闭...')
  // 关闭HTTP服务
  server.close(() => {
    console.log('HTTP服务已关闭')
  })
  
  // 关闭Redis连接
  try {
    redis.client.disconnect()
    console.log('Redis连接已关闭')
  } catch (err) {
    console.error('关闭Redis连接时出错:', err)
  }
  
  // 3秒后强制退出
  setTimeout(() => {
    console.log('强制退出进程')
    process.exit(0)
  }, 3000)
})